#ifndef DBFILE_H
#define DBFILE_H

#include <iostream>
#include "File.h"
#include "BigQ.h"

typedef enum {heap, sorted, tree} fType;
typedef enum {reading, writing} pType;

struct SortInfo {
	OrderMaker *myOrder;
	int runLength;
};

class GenericDBFile{

    protected:
        pType pageType;
        char *f_path;
        Page *page;
        File file;
        int currentPage;

        /**
         *Helper function to get the file length correctly
         *@return file length
         */
        int FileLength();

    public:
        GenericDBFile();

        virtual ~GenericDBFile();

        virtual int Create (char *fpath, fType file_type, void *startup);

        virtual int Open (char *fpath);

        virtual int Close ();

        virtual void Load (Schema &myschema, char *loadme);

        virtual void MoveFirst ();

        virtual void Add (Record &addme);

        virtual int GetNext (Record &fetchme);

        virtual int GetNext (Record &fetchme, CNF &cnf, Record &literal);
};

class HeapDBFile : public GenericDBFile{
    private:
        int currentRecord;
        int loadedPage;

        void WritePageToFile();

    public:
        HeapDBFile() ;
        ~HeapDBFile();

        int Create (char *fpath, fType file_type, void *startup);

        int Open (char *fpath);

        int Close();

        void Load (Schema &myschema, char *loadme);

        void MoveFirst ();

        void Add (Record &addme);

        int GetNext (Record &fetchme);

        int GetNext (Record &fetchme, CNF &cnf, Record &literal);
};

class SortedDBFile : public GenericDBFile{

    private:
        int runLen;
        bool queryOrderMakerCreated;
        bool queryOrderMakerFailed;
        bool foundMatch;
        OrderMaker *orderMaker;
        OrderMaker queryOrderMaker;
        OrderMaker literalOrderMaker;
        BigQ* bigQ;
        Pipe* in;
        Pipe* out;

        char filePath[250];

        void Merge();
        void SwitchToReading();
        void SwitchToWritting();
        void AddToFile(File& mergeFile, Page &writtingPage, Record &record);
        void BinarySearch(Record &fetchme, Record &literal);

    public:
        SortedDBFile() ;
        ~SortedDBFile();

        int Create(char *fpath, fType file_type, void *startup);

        int Open(char *fpath);

        int Close();

        void Load(Schema &myschema, char *loadme);

        void MoveFirst();

        void Add(Record &addme);

        int GetNext(Record &fetchme);

        int GetNext(Record &fetchme, CNF &cnf, Record &literal);
};

class DBFile {

    private:
        /**
         *pointer to the type of db file
        */
        GenericDBFile *genericDBFile;

    public:

        /**
         *constructors
        */
        DBFile ();
        ~DBFile ();

        /**
         *Creates the DBFile
         *@param fpath file location
         *@param file_type {heap,sorted,tree}
         *@param startup ??
         *@return 1 on success and a zero on failure
         */
        int Create (char *fpath, fType file_type, void *startup);

        /**
         *Open the specified DBFile
         *@param fpath location of the file
         *@return 1 on success and a zero on failure
         */
        int Open (char *fpath);

        /**
         *Closes the DBFile
         *@return 1 on success and a zero on failure
         */
        int Close ();

        /**
         *Bulk loads the DBFile instance from a text file, appending
         *new data to it using the SuckNextRecord function from the Record class
         *@param schema schema of the file used for bulk load
         *@param loadpath location of the file
         */
        void Load (Schema &myschema, char *loadpath);

        /**
         *Move the pointer to the first record in the file
         */
        void MoveFirst ();

        /**
         *Adds a record to the end of the file and consumes the record
         *@param addme record to add
         */
        void Add (Record &addme);

        /**
         *Gets the next record from the file and returns it to the user
         *@param fetchme retrieved record
         *@return 1 on success and a zero on failure (e.g. EOF)
         */
        int GetNext (Record &fetchme);

        /**
         *Gets next record in the file that is accepted by the selection predicate
         *@param fetchme retrieved record
         *@param cnf selection predicate
         *@param literal used to check the selection predicate, and is created when the parse tree for the CNF is processed
         *@return 1 on success and a zero on failure (e.g. EOF)
         */
        int GetNext (Record &fetchme, CNF &cnf, Record &literal);
};
#endif
